{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "# 索引、切片、连接、换位 Indexing, Slicing, Joining, Mutating Ops"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.chunk\n",
    "torch.chunk(tensor, chunks, dim=0)  \n",
    "在给定维度(轴)上将输入张量进行分块儿。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.gather\n",
    "torch.gather(input, dim, index, out=None) → Tensor  \n",
    "沿给定轴 dim ，将输入索引张量 index 指定位置的值进行聚合。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[1., 1.],\n",
       "        [4., 3.]])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t = torch.Tensor([[1, 2], [3, 4]])\n",
    "torch.gather(t, 1, torch.LongTensor([[0, 0], [1, 0]]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.index_select\n",
    "torch.index_select(input, dim, index, out=None) → Tensor  \n",
    "沿着指定维度对输入进行切片，取 index 中指定的相应项( index 为一个LongTensor)，然后返回到一个新的张量，返回的张量与原始张量_Tensor_有相同的维度(在指定轴上)。  \n",
    "**注意：**返回的张量不与原始张量共享内存空间。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 1.0117, -0.4018, -0.2433,  1.4207],\n",
       "        [-1.0441,  0.8142,  0.5578, -0.4124],\n",
       "        [ 0.4011, -0.1691,  0.6862,  0.5115]])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.randn(3, 4)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 1.0117, -0.4018, -0.2433,  1.4207],\n",
       "        [ 0.4011, -0.1691,  0.6862,  0.5115]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "indices = torch.LongTensor([0, 2])\n",
    "torch.index_select(x, 0, indices)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 1.0117, -0.2433],\n",
       "        [-1.0441,  0.5578],\n",
       "        [ 0.4011,  0.6862]])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.index_select(x, 1, indices)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.masked_select\n",
    "torch.masked_select(input, mask, out=None) → Tensor  \n",
    "根据掩码张量 mask 中的二元值，取输入张量中的指定项( mask 为一个 ByteTensor)，将取值返回到一个新的1D张量，张量 mask 须跟 input 张量有相同数量的元素数目，但形状或维度不需要相同。 \n",
    "**注意：**返回的张量不与原始张量共享内存空间。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.1195, -0.6053,  1.1944, -0.6315],\n",
       "        [ 0.9335, -0.8966, -1.3796,  1.4862],\n",
       "        [-0.6084, -1.0672, -1.4919,  2.2267]])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.randn(3, 4)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0, 0, 1, 0],\n",
       "        [1, 0, 0, 1],\n",
       "        [0, 0, 0, 1]], dtype=torch.uint8)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mask = x.ge(0.5)\n",
    "mask"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1.1944, 0.9335, 1.4862, 2.2267])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.masked_select(x, mask)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.nonzero\n",
    "torch.nonzero(input, out=None) → LongTensor  \n",
    "返回一个包含输入 input 中非零元素索引的张量。输出张量中的每行包含输入中非零元素的索引。  \n",
    "如果输入 input 有 n 维，则输出的索引张量 output 的形状为 z x n, 这里 z 是输入张量 input 中所有非零元素的个数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0],\n",
       "        [1],\n",
       "        [2],\n",
       "        [4]])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.nonzero(torch.Tensor([1,1,1,0,1]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0, 0],\n",
       "        [1, 1],\n",
       "        [2, 2],\n",
       "        [3, 3]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.nonzero(torch.Tensor([[0.6, 0.0, 0.0, 0.0],\n",
    "                            [0.0, 0.4, 0.0, 0.0],\n",
    "                            [0.0, 0.0, 1.2, 0.0],\n",
    "                            [0.0, 0.0, 0.0,-0.4]]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.squeeze\n",
    "torch.squeeze(input, dim=None, out=None)  \n",
    "将输入张量形状中的 1 去除并返回。 如果输入是形如$(A \\times1 \\times B \\times 1 \\times C \\times 1 \\times D)$，那么输出形状就为：$(A \\times B \\times C \\times D)$  \n",
    "当给定 dim 时，那么挤压操作只在给定维度上。例如，输入形状为:$(A \\times 1 \\times B)$,\n",
    "squeeze(input, 0)将会保持张量不变，只有用 squeeze(input, 1)，形状会变成$(A \\times B)$。  \n",
    "**注意：**返回张量与输入张量共享内存，所以改变其中一个的内容会改变另一个。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([2, 1, 2, 1, 2])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.zeros(2, 1, 2, 1, 2)\n",
    "x.size()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([2, 2, 2])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = torch.squeeze(x)\n",
    "y.size()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([2, 2, 1, 2])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = torch.squeeze(x, 1)\n",
    "y.size()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.t\n",
    "torch.t(input, out=None) → Tensor  \n",
    "输入一个矩阵（2维张量），并转置0, 1维。可以被视为函数 transpose(input, 0, 1) 的简写函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[-0.2231,  0.9052, -0.2594],\n",
       "        [-0.0181, -1.3110,  0.9367]])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.randn(2, 3)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[-0.2231, -0.0181],\n",
       "        [ 0.9052, -1.3110],\n",
       "        [-0.2594,  0.9367]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.t(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.transpose\n",
    "torch.transpose(input, dim0, dim1, out=None) → Tensor  \n",
    "返回输入矩阵 input 的转置。交换维度 dim0 和 dim1 。 输出张量与输入张量共享内存，所以改变其中一个会导致另外一个也被修改。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.7656,  0.8740, -0.7367],\n",
       "        [-0.2518,  0.8631, -0.0509]])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.randn(2, 3)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.7656, -0.2518],\n",
       "        [ 0.8740,  0.8631],\n",
       "        [-0.7367, -0.0509]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.transpose(x, 0 ,1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.unsqueeze\n",
    "torch.unsqueeze(input, dim, out=None)  \n",
    "返回一个新的张量，对输入的制定位置插入维度 1  \n",
    "**注意：**返回张量与输入张量共享内存，所以改变其中一个的内容会改变另一个。  \n",
    "如果 dim 为负，则将会被转化$dim+input.dim()+1$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[1., 2., 3., 4.]])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.Tensor([1, 2, 3, 4])\n",
    "torch.unsqueeze(x, 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[1.],\n",
       "        [2.],\n",
       "        [3.],\n",
       "        [4.]])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.unsqueeze(x, 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 随机抽样 Random sampling"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.bernoulli\n",
    "torch.bernoulli(input, out=None) → Tensor  \n",
    "从伯努利分布中抽取二元随机数(0 或者 1)。  \n",
    "输入张量须包含用于抽取上述二元随机值的概率。 因此，输入中的所有值都必须在［0,1］区间，即$0 \\leqslant input_i \\leqslant 1$  \n",
    "输出张量的第 i 个元素值， 将会以输入张量的第 i 个概率值等于 1 。  \n",
    "返回值将会是与输入相同大小的张量，每个值为0或者1。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0.0939, 0.0576, 0.8169],\n",
       "        [0.3046, 0.5536, 0.1575],\n",
       "        [0.1452, 0.1641, 0.4408]])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = torch.Tensor(3, 3).uniform_(0, 1)\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0., 1., 0.],\n",
       "        [0., 0., 0.],\n",
       "        [1., 0., 0.]])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.bernoulli(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[1., 1., 1.],\n",
       "        [1., 1., 1.],\n",
       "        [1., 1., 1.]])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = torch.ones(3, 3)\n",
    "torch.bernoulli(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0., 0., 0.],\n",
       "        [0., 0., 0.],\n",
       "        [0., 0., 0.]])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = torch.zeros(3, 3)\n",
    "torch.bernoulli(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.multinomial\n",
    "torch.multinomial(input, num_samples,replacement=False, out=None) → LongTensor  \n",
    "返回一个张量，每行包含从 input 相应行中定义的多项分布中抽取的 num_samples 个样本。  \n",
    "**[注意]:** 输入 input 每行的值不需要总和为1 (这里我们用来做权重)，但是必须非负且总和不能为0。  \n",
    "当抽取样本时，依次从左到右排列(第一个样本对应第一列)。  \n",
    "如果输入 input 是一个向量，输出 out 也是一个相同长度 num_samples 的向量。如果输入input 是有$m$行的矩阵，输出 out 是形如$m \\times n$的矩阵。  \n",
    "如果参数 replacement 为 True，则样本抽取可以重复。否则，一个样本在每行不能被重复抽取。  \n",
    "参数 num_samples 必须小于 input 长度(即 input 的列数，如果是 input 是一个矩阵)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1, 2])"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "weights = torch.Tensor([0, 10, 3, 0])\n",
    "torch.multinomial(weights, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1, 1, 1, 2])"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.multinomial(weights, 4, replacement=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### torch.normal()\n",
    "torch.normal(means, std, out=None)  \n",
    "返回一个张量，包含从给定参数 means , std 的离散正态分布中抽取随机数。 均值 means 是一个张量，包含每个输出元素相关的正态分布的均值。 std 是一个张量，包含每个输出元素相关的正态分布的标准差。均值和标准差的形状不须匹配，但每个张量的元素个数须相同。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([-0.1886,  0.7723,  2.2527,  4.5663,  4.5461,  6.1170,  6.3687,  7.8762,\n",
       "         8.8305,  9.7696])"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.normal(mean=torch.arange(1., 11.), std=torch.arange(1., 0., -0.1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([ 1.5971, -0.4293,  3.1326,  1.1746,  4.8121])"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.normal(mean=0.5, std=torch.arange(1., 6.))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1.1260, 1.0013, 2.9010, 4.6049, 4.4163])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.normal(mean=torch.arange(1., 6.))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
